package com.klangner.atarigo.model;

import java.util.Collection;
import java.util.Iterator;
import java.util.Vector;

import com.klangner.game.board.BoardPosition;
import com.klangner.game.board.IBoard;

/**
 * This class analyzes stones on the board and assign them to the groups.
 * Stone belongs to group <=> shares liberties with it
 */
public class GroupingAlgorithm {

	/** groups on board */
	private StonesGroup[][]	groupBoard;

	/** Group collection */
	private Vector<StonesGroup>	groups = new Vector<StonesGroup>();
	
	/** Board size (cached from IBoard) */
	private int boardSize;
	
	
	/**
	 * Constructor
	 */
	public GroupingAlgorithm(IBoard board){
		
		boardSize = board.getSize();

		groupBoard = new StonesGroup[boardSize][boardSize];
		createGroups(board);
		findGroupLiberties();
	}

	/**
	 * Get groups
	 */
	public Collection<StonesGroup> getGroups(){
		return groups;
	}
	

	/**
	 * Parse board and group stones.
	 * Algorithm description
	 * If stone is found check 
	 *   If (x-1, y) or (x, y-1) contains group with the same color
	 *     add to this group
	 *   else
	 *     create new group
	 * 
	 * @param board
	 */
	private void createGroups(IBoard board){
		
		for(int y = 0; y < boardSize; y ++){
			for(int x = 0; x < boardSize; x ++){
				
				int color = board.getStone(x, y);
				if(IBoard.NO_STONE != color){
					
					StonesGroup group = null;
					
					if(x > 0 && board.getStone(x-1, y) == color){
						group = groupBoard[x-1][y];
					}
					
					if(y > 0 && board.getStone(x, y-1) == color){
						if(group != null && groupBoard[x][y-1] != group){
							StonesGroup group2 = groupBoard[x][y-1];
							group.merge(group2);
							replaceGroup(group2, group);
						}
						else{
							group = groupBoard[x][y-1];
						}
					}
					
					if(group == null){
						group = new StonesGroup(color);
						groups.add(group);
					}

					group.addStone(new BoardPosition(x, y));
					groupBoard[x][y] = group;
				}
			}
		}
	}

	/**
	 * find group liberties
	 */
	private void findGroupLiberties() {

		for(int y = 0; y < boardSize; y ++){
			for(int x = 0; x < boardSize; x ++){
				
				if(groupBoard[x][y] == null){
					BoardPosition pos = new BoardPosition(x, y);
					if(x > 0 && groupBoard[x-1][y] != null){
						groupBoard[x-1][y].addLiberty(pos);
					}
					if(x < boardSize-1 && groupBoard[x+1][y] != null){
						groupBoard[x+1][y].addLiberty(pos);
					}
					if(y > 0 && groupBoard[x][y-1] != null){
						groupBoard[x][y-1].addLiberty(pos);
					}
					if(y < boardSize-1 && groupBoard[x][y+1] != null){
						groupBoard[x][y+1].addLiberty(pos);
					}
				}
			}
		}
	}

	/**
	 * Replace group information on board
	 * @param oldGroup old group
	 * @param newGroup new one
	 */
	private void replaceGroup(StonesGroup oldGroup, StonesGroup newGroup) {
		
		Iterator<BoardPosition> it = oldGroup.getStones().iterator();
		
		while( it.hasNext() ){
		
			BoardPosition pos = it.next();
			groupBoard[pos.getX()][pos.getY()] = newGroup;
		}

		groups.remove(oldGroup);
		
	}
}
